<!--
 * @Description:It is troublesome to implement radio button group in the form. So it is extracted independently as a separate component
-->
<template>
	<RadioGroup v-bind="attrs" button-style="solid" @change="handleChange">
		<template v-for="item in getOptions" :key="`${item.value}`">
			<RadioButton v-if="props.isBtn" :value="item.value" :disabled="item.disabled">
				{{ item.label }}
			</RadioButton>
			<Radio v-else :value="item.value" :disabled="item.disabled">
				{{ item.label }}
			</Radio>
		</template>
	</RadioGroup>
</template>
<script lang="ts">
import { defineComponent, PropType, ref, watchEffect, computed, unref, watch } from 'vue';
import { Radio } from 'ant-design-vue';
import { isFunction } from '@/utils/is';
import { get, omit } from 'lodash-es';
import { useAttrs } from '@/hooks/core/useAttrs';
type OptionsItem = { label: string; value: string | number | boolean; disabled?: boolean };

export default defineComponent({
	name: 'ApiRadioGroup',
	components: {
		RadioGroup: Radio.Group,
		RadioButton: Radio.Button,
		Radio,
	},
	props: {
		api: {
			type: Function as PropType<(arg?: Recordable | string) => Promise<OptionsItem[]>>,
			default: null,
		},
		params: {
			type: [Object, String] as PropType<Recordable | string>,
			default: () => ({}),
		},
		isBtn: {
			type: [Boolean] as PropType<boolean>,
			default: false,
		},
		numberToString: { type: Boolean as PropType<boolean>, default: null },
		resultField: { type: String as PropType<string>, default: '' },
		labelField: { type: String as PropType<string>, default: 'label' },
		valueField: { type: String as PropType<string>, default: 'value' },
		immediate: { type: Boolean as PropType<boolean>, default: true },
	},
	emits: ['options-change', 'change'],
	setup(props, { emit }) {
		const options = ref<OptionsItem[]>([]);
		const loading = ref(false);
		const isFirstLoad = ref(true);
		const attrs = useAttrs();

		// Processing options value
		const getOptions = computed(() => {
			const { labelField, valueField, numberToString } = props;

			return unref(options).reduce((prev, next: Recordable) => {
				if (next) {
					const value = next[valueField];
					prev.push({
						label: next[labelField],
						value: numberToString ? `${value}` : value,
						...omit(next, [labelField, valueField]),
					});
				}
				return prev;
			}, [] as OptionsItem[]);
		});

		watchEffect(() => {
			props.immediate && fetch();
		});

		watch(
			() => props.params,
			() => {
				!unref(isFirstLoad) && fetch();
			},
			{ deep: true },
		);

		async function fetch() {
			const api = props.api;
			if (!api || !isFunction(api)) return;
			options.value = [];
			try {
				loading.value = true;
				const res = await api(props.params);
				if (Array.isArray(res)) {
					options.value = res;
					emitChange();
					return;
				}
				if (props.resultField) {
					options.value = get(res, props.resultField) || [];
				}
				emitChange();
			} catch (error) {
				console.warn(error);
			} finally {
				loading.value = false;
			}
		}

		function emitChange() {
			emit('options-change', unref(getOptions));
		}

		function handleChange(e) {
			emit('change', e?.target?.value);
		}

		return { getOptions, attrs, loading, handleChange, props };
	},
});
</script>
